package kyuu.acshmily.comment
{
	import flash.geom.Point;
	
	import mx.containers.Canvas;
	import mx.effects.Effect;
	import mx.effects.Move;
	import mx.effects.Pause;
	import mx.effects.easing.Linear;
	import mx.events.EffectEvent;
	import mx.events.FlexEvent;
	import mx.events.ResizeEvent;

	/**
	 * 弹幕舞台类
	 */
	public class CommentsStage extends Canvas
	{
		// 弹幕舞台的分类
		public const STATIC_TOP:uint = 1;
		public const STATIC_BOTTOM:uint = 2;
		public const DYNAMIC_UP:uint = 3;
		public const DYNAMIC_DOWN:uint = 4;
		public const DYNAMIC_LEFT:uint = 5;
		public const DYNAMIC_RIGHT:uint = 6;

		// 舞台类型
		private var _mode:uint = 0;
		// 所有弹幕组件列表（按照从上到下的顺序排放）
		private var _commentArray:Array = new Array();
		
		// 保存所有特效列表
		private var _effectArray:Array = new Array();

		public function CommentsStage(mode:uint){
			super();
			// 记录舞台类型
			_mode = mode;
			// 禁用滚动条
			horizontalScrollPolicy = "off";
			verticalScrollPolicy = "off";
			
			addEventListener(FlexEvent.CREATION_COMPLETE, creationCompleteHandler);
		}

		/**
		 * 向本舞台增加一条弹幕
		 * @param info - 弹幕信息XML
		 * @param isPlay - 是否马上播放效果
		 */
		public function addComment(info:XML, isPlay:Boolean):void{
			// 构造一个弹幕
			var cl:CommentLabel = new CommentLabel();
			this.addChild(cl);
			cl.setComment(info);

			// 设置起始位置
			var pt1:Point = getStartPosition(cl);
			cl.x = pt1.x;
			cl.y = pt1.y;

			if(info.@mode < DYNAMIC_UP){
				cl.visible = true;

				// 对于静止弹幕，使用Pause特效
				var pauseEff:Pause = new Pause(cl);
				pauseEff.duration = cl.hasHideEffect() ? 4000 : 5000;
				pauseEff.addEventListener(EffectEvent.EFFECT_END, effectEndHandler);
				_effectArray.push(pauseEff);

				pauseEff.play();
				if(!isPlay) notifyPause();
			}
			else{
				cl.visible = true;

				// 对于动态弹幕，使用Move特效
				var pt2:Point = getEndPosition(cl, pt1);
				var moveEff:Move = new Move(cl);
				moveEff.duration = 5000;
				moveEff.easingFunction = Linear.easeNone;
				moveEff.addEventListener(EffectEvent.EFFECT_END, effectEndHandler);
				moveEff.xFrom = pt1.x;
				moveEff.yFrom = pt1.y;
				moveEff.xTo = pt2.x;
				moveEff.yTo = pt2.y;
				_effectArray.push(moveEff);

				moveEff.play();
				if(!isPlay) notifyPause();
			}
		}

		/**
		 * 通知弹幕舞台暂停播放
		 */
		public function notifyPause():void{
			var i:int;
			// 暂停所有效果
			for(i=0; i<_effectArray.length; i++){
				var eff:Effect = _effectArray[i] as Effect;
				if(eff == null) continue;
				eff.pause();
			}
			// 通知弹幕暂停效果
			var children:Array = getChildren();
			for(i=0; i<children.length; i++){
				var cl:CommentLabel = children[i] as CommentLabel;
				if(cl == null) continue;
				cl.notifyPause();
			}
		}

		/**
		 * 通知弹幕舞台继续播放
		 */
		public function notifyResume():void{
			// 恢复所有效果
			for(var i:int = 0; i < _effectArray.length; i++){
				var eff:Effect = _effectArray[i] as Effect;
				if(eff == null) continue;
				eff.resume();
			}
			// 通知弹幕恢复效果
			var children:Array = getChildren();
			for(i=0; i<children.length; i++){
				var cl:CommentLabel = children[i] as CommentLabel;
				if(cl == null) continue;
				cl.notifyResume();
			}
		}

		/**
		 * 过滤弹幕
		 * @param locked - 是否显示固定弹幕
		 * @param normal - 是否显示普通弹幕
		 */
		public function setCommentsVisible(locked:Boolean, normal:Boolean):void{
			var cmnts:Array = this.getChildren();
			for(var i:int=0; i<cmnts.length; i++){
				var cl:CommentLabel = cmnts[i] as CommentLabel;
				if(cl == null) continue;

				// 对锁定弹幕的判断
				if(locked){
					if(cl.isLocked && !cl.visible) cl.showWithoutEffect(true);
				}
				else{
					if(cl.isLocked && cl.visible) cl.showWithoutEffect(false);
				}

				// 对普通弹幕的判断
				if(normal){
					if(!cl.isLocked && !cl.visible) cl.showWithoutEffect(true);
				}
				else{
					if(!cl.isLocked && cl.visible) cl.showWithoutEffect(false);
				}
			}
		}

		/**
		 * 清空所有弹幕
		 * 用户手工调整视频时间时，调用此方法
		 */
		public function clearComments():void{
			var i:int;
			for(i=0; i<_effectArray.length; i++){
				var eff:Effect = _effectArray[i] as Effect;
				if(eff == null) continue;
				eff.stop();
				eff.target = null;
				removeItemFromArray(_effectArray, eff);
				eff = null;
			}

			var children:Array = getChildren();
			for(i=0; i<children.length; i++){
				var cl:CommentLabel = children[i] as CommentLabel;
				if(cl == null) continue;
				removeItemFromArray(_commentArray, cl);
				removeChild(cl);
				cl = null;
			}
		}

		/**
		 * 运动效果完成时的事件处理函数
		 */
		private function effectEndHandler(e:EffectEvent):void{
			var eff:Effect = e.target as Effect;
			if(eff == null) return;
			eff.removeEventListener(EffectEvent.EFFECT_END, effectEndHandler);

			var cl:CommentLabel = eff.target as CommentLabel;
			if(cl == null) return;

			eff.target = null;
			if(eff is Pause){
				if(cl.hasHideEffect()){
					cl.visible = false;
					cl.addEventListener(EffectEvent.EFFECT_END, hideEffectEndHandler);
				}
				else{
					removeItemFromArray(_commentArray, cl);
					removeChild(cl);
					cl = null;
				}
				
			}
			else if(eff is Move){
				removeItemFromArray(_commentArray, cl);
				try{
					removeChild(cl);
				}
				catch(err:Error){
					trace(err.message);
				}
				cl = null;
			}

			// 释放该特效
			removeItemFromArray(_effectArray, eff);
		}

		/**
		 * 弹幕内部效果完成时的事件处理函数
		 */
		private function hideEffectEndHandler(e:EffectEvent):void{
			var cl:CommentLabel = e.target as CommentLabel;
			if(cl == null) return;
			
			if(cl.activeEffects != null && cl.activeEffects.length > 1) return;

			// 移除监听器
			cl.removeEventListener(EffectEvent.EFFECT_END, hideEffectEndHandler);

			// 移除弹幕组件
			removeItemFromArray(_commentArray, cl);
			try{ removeChild(cl); }
			catch(err:Error){}
			cl = null;
		}

		/**
		 * 创建完成时的事件处理函数
		 * 创建完成后，会开始监听resize事件
		 */
		private function creationCompleteHandler(e:FlexEvent):void{
			removeEventListener(FlexEvent.CREATION_COMPLETE, creationCompleteHandler);
			addEventListener(ResizeEvent.RESIZE, resizeHandler);
		}

		/**
		 * 调整大小时的事件处理函数
		 * 可被子类覆盖，下一版舞台将做成多态的
		 */
		protected function resizeHandler(e:ResizeEvent):void{
			var newWidth:Number = this.width;
			var newHeight:Number = this.height;
			
			var i:uint;
			var cl:CommentLabel;
			if(_mode < DYNAMIC_UP){
				// 遍历组件，静态弹幕使用
				for(i=0; i<_commentArray.length; i++){
					cl = _commentArray[i] as CommentLabel;
					if(cl == null) continue;
	
					switch(_mode){
						case STATIC_TOP:
							cl.x = (width - cl.width) / 2;
							cl.y = cl.logicY % height;
							break;
						case STATIC_BOTTOM:
							cl.x = (width - cl.width) / 2;
							cl.y = cl.logicY % height + height;
							break;
						case DYNAMIC_UP:
							// 暂不实现
							break;
						case DYNAMIC_DOWN:
							// 暂不实现
							break;
						case DYNAMIC_LEFT:
							break;
						case DYNAMIC_RIGHT:
							break;
					}
	
				}
			}
			else{
				// 遍历效果，动态弹幕使用
				for(i=0; i<_effectArray.length; i++){
					var moveEff:Move = _effectArray[i] as Move;
					if(moveEff == null) continue;
					cl = moveEff.target as CommentLabel;
					if(cl == null) continue;

					var newDur:Number = 0;//moveEff.duration - moveEff.playheadTime;
					var percent:Number = 0;//moveEff.playheadTime / moveEff.duration;
					moveEff.stop();
					// 重新定义移动效果
					moveEff.duration = newDur;
					trace(newDur);
					switch(_mode){
						case STATIC_TOP:
							break;
						case STATIC_BOTTOM:
							break;
						case DYNAMIC_UP:
							// 暂不实现
							break;
						case DYNAMIC_DOWN:
							// 暂不实现
							break;
						case DYNAMIC_LEFT:
							moveEff.xFrom = width * (1 - percent);
							moveEff.yFrom = cl.logicY % height;
							moveEff.yTo = cl.logicY % height;
							cl.x = moveEff.xFrom;
							cl.y = moveEff.yFrom;
							trace(moveEff.xFrom + "," + moveEff.xTo + "," + moveEff.yFrom + "," + moveEff.yTo);
							break;
						case DYNAMIC_RIGHT:
							moveEff.xFrom = width * percent;
							moveEff.xTo = width;
							moveEff.yFrom = cl.logicY % height + height;
							moveEff.yTo = cl.logicY % height + height;
							cl.x = moveEff.xFrom;
							cl.y = moveEff.yFrom;
							trace(moveEff.xFrom + "," + moveEff.xTo + "," + moveEff.yFrom + "," + moveEff.yTo);
							break;
					}
					moveEff.play();
					
				}
			}
		}

		/**
		 * 获取弹幕的起始坐标
		 */
		private function getStartPosition(cl:CommentLabel):Point{
			var pt:Point = new Point(0, 0);
			switch(_mode){
				case STATIC_TOP:
					pt.x = (this.width - cl.width) / 2;
					pt.y = getInitYPosition4TopComment(cl);
					break;
				case STATIC_BOTTOM:
					pt.x = (this.width - cl.width) / 2;
					pt.y = getInitYPosition4BottomComment(cl);
					break;
				case DYNAMIC_UP:
					pt.x = this.width - cl.width;
					pt.y = this.height;
					break;
				case DYNAMIC_DOWN:
					pt.x = 0;
					pt.y = 0 - cl.height;
					break;
				case DYNAMIC_LEFT:
					pt.x = this.width;
					//pt.y = 0;
					pt.y = getInitYPosition4TopComment(cl);
					break;
				case DYNAMIC_RIGHT:
					pt.x = 0 - cl.width;
					//pt.y = this.height - cl.height;
					pt.y = getInitYPosition4BottomComment(cl);
					break;
				default:
					break;
			}
			return pt;
		}

		/**
		 * 获取弹幕的运动终止坐标
		 */
		private function getEndPosition(cl:CommentLabel, startPt:Point):Point{
			var pt:Point = new Point(0, 0);
			switch(_mode){
				case STATIC_TOP:
				case STATIC_BOTTOM:
					pt = startPt;
					break;
				case DYNAMIC_UP:
					pt.x = startPt.x;
					pt.y = 0 - cl.height;
					break;
				case DYNAMIC_DOWN:
					pt.x = startPt.x;
					pt.y = this.height;
					break;
				case DYNAMIC_LEFT:
					pt.x = 0 - cl.width;
					pt.y = startPt.y;
					break;
				case DYNAMIC_RIGHT:
					pt.x = this.width;
					pt.y = startPt.y;
					break;
				default:
					break;
			}
			return pt;
		}

		/**
		 * 为顶端顶固定弹幕计算初始纵坐标
		 * @param cl - 要计算纵坐标的弹幕组件
		 * @return 弹幕的纵坐标
		 */
		private function getInitYPosition4TopComment(cl:CommentLabel):Number{
			var yPos:Number = 0;
			var index:uint = 0;

			for(var i:int=0; i<_commentArray.length; i++){
				var cmnt:CommentLabel = _commentArray[i] as CommentLabel;
				// 判断新的弹幕是否可以放在最上面
				if(i == 0 && cmnt.logicY > cl.height) break;

				// 判断弹幕是否要放在最后
				if(i == (_commentArray.length - 1)){
					cl.logicY = cmnt.logicY + cmnt.height;
					index = i + 1;
					break;
				}

				// 其他情况，遍历
				var cmnt2:CommentLabel = _commentArray[i+1] as CommentLabel;
				if(cmnt2.logicY - cmnt.logicY - cmnt.height >= cl.height){
					cl.logicY = cmnt.logicY + cmnt.height;
					index = i + 1;
					break;
				}
				
			}
			_commentArray.splice(index, 0, cl);

			// 处理被卡住的弹幕
			if((cl.logicY % this.height) > ((cl.logicY + cl.height) % this.height)){
				cl.logicY = Math.ceil(cl.logicY / this.height) * this.height;
			}
			yPos = cl.logicY % this.height;
			
			return yPos;
		}

		/**
		 * 为底端固定弹幕计算初始纵坐标
		 * @param cl - 要计算纵坐标的弹幕组件
		 * @return 弹幕的纵坐标
		 */
		private function getInitYPosition4BottomComment(cl:CommentLabel):Number{
			var yPos:Number = 0 - cl.height;
			var index:uint = 0;

			cl.logicY = 0 - cl.height;

			for(var i:int=0; i<_commentArray.length; i++){
				var cmnt:CommentLabel = _commentArray[i] as CommentLabel;
				// 判断新的弹幕是否可以放在最下面
				if(i == 0 && (cmnt.logicY + cmnt.height + cl.height) <= 0 ) break;

				// 是否已经检索到最后
				if(i == (_commentArray.length - 1)){
					cl.logicY = cmnt.logicY - cl.height;
					index = i + 1;
					break;
				}
				
				// 其他情况，遍历
				var cmnt2:CommentLabel = _commentArray[i+1] as CommentLabel;
				if(cmnt.logicY - cl.height >= cmnt2.logicY + cmnt2.height){
					cl.logicY = cmnt.logicY - cl.height;
					index = i + 1;
					break;
				}
				
			}
			// 处理被卡住的弹幕
			if((cl.logicY % this.height) > ((cl.logicY + cl.height) % this.height)){
				cl.logicY = Math.ceil(cl.logicY / this.height) * this.height - cl.height;
			} 
			_commentArray.splice(index, 0, cl);
			yPos = cl.logicY % height + height;
			
			return yPos;
		}

		/**
		 * 从数组中删除指定的元素
		 * @param arr - 数组
		 * @param item - 要删除的原色
		 */
		private function removeItemFromArray(arr:Array, item:Object):void{
			if(arr == null) return;
			var itemIndex:int = arr.indexOf(item);
			if(item < 0) return;
			arr.splice(itemIndex, 1);
		}
	}
}